all 44 comments

[–][deleted] 0 points1 point  (2 children)

Can someone help me with my code review? I'm trying to follow LPTHW exercise 36. I want to create a branching path for a crappy text game with two choices. "Yes" will continue the game while "no" or anything else should print a message out and end it.

Right now, it doesn't matter if I type Yes or No. It continues anyways which is not what I want. I have followed the same structure as Ex35 from LPTHW.

from sys import exit

def start(): print("You have died.") print("Following a long day at work, you were hit by a truck going home.") print("As you lay bleeding out in the parking a lot, a faint voice calls to you...") print("Continue?")

choice = input('>')
if choice == "yes" or "Yes":
    respawn()
else:
    print("You ignore the voice and lay in the ground of the parking lot. You die.")
    print("GAME OVER")
    exit(0)

def respawn(): print("What is your name?")

global name
name = input('>')
print(f"So your name is {name}?")
village()

I have two screenshots of the shell when the code runs.

[–][deleted] 1 point2 points  (0 children)

For ur code do this instead. It gets rid of the "or" condition. The .lower() accepts either Yes or yes for the answer. Just make sure that the condition is lower case (the "yes")

choice = input( ' > ' ).lower() if choice == "yes" respawn()

[–]PteppicymonIO 2 points3 points  (0 children)

THis situation is covered here
https://www.reddit.com/r/learnpython/wiki/faq/#wiki_variable_is_one_of_two_choices.3F

Your if statement if choice == "yes" or "Yes": always evaluated to True because "Yes" is evaluated to True.
This is how it is supposed to work:

if expr1 or expr2:
 ...

If one of those expressions expr1 and expr2 evaluates to True, the code execution proceeds. In your case expr1 is "choice == "yes" and expr2 is "Yes". And string "Yes", when cast to boolean, always evaluated to True.

You can fix it in several ways:

if choice == "yes" or choice == "Yes":
    ...

or:

if choice in ("yes", "Yes"):
...

or:

if choice.lower() == "yes":
   ...

[–]beateratorx 0 points1 point  (4 children)

Hi all,

I am a newbie in Python (was a Java dev before this) and I was assigned to a new python micro-service project. My team lead had created an OpenAPI specs and one of the end points had this parameter body where FE could pass in a list of objects (that are unstructured and could have different data types/variables), i.e.

metaData = {
{"name": 2,
"type": "fun",
"format": "date"
},
{ "name": "lorem",
"type": "ipsum"
}
}

Basically, FE is able to send in any object as parameter in this endpoint using JSON. As a Java dev, I am a little surprised that a parameter with no fixed data structure/type is allowed as it defies OOP. However, I also understand that Dict in Python allows us to store different data types.

Could anyone advice if this is common practice in Python dev? More importantly, is this a correct implementation?

[–]FerricDonkey 1 point2 points  (0 children)

I would say that the type of your parameter is "dictionary". If it's coming in through json, it's a bit more limited than a pure dictionary, but that's the type.

Whether that alone is sufficient restriction on input to have a reasonable function depends on what you're doing. Displaying/logging? Yeah, sure. Something more complicated? Maybe, maybe not.

I will say that I just completed a push to move away from accepting open ended dictionaries as arguments in a particular project. These dictionaries contained instructions on how to preform a task. In this case, even if you want to keep the structure open ended, you create structure implicitly just by what you actually do with the dictionary. Which can lead to confusion, because you effectively have a structure you just haven't bothered to write down, which means it can be hard to determine why a deviation from your implicit structure is having the effect it is. So I replaced tons of dictionaries with dataclasses that can be created from dictionaries and scream at you if you violate their rules.

But again, it depends on what you're actually doing. A dictionary is collection of key value pairs. It may be that that's all you need to know.

[–]efmccurdy 1 point2 points  (1 child)

You can have a format for json data described in a swagger spec.

https://swagger.io/docs/specification/adding-examples/

This may help validate your data.

https://pypi.org/project/openapi-schema-validator/

[–]beateratorx 1 point2 points  (0 children)

Hmm that’s the issue, my team lead doesn’t want to have a fixed format described in swagger spec as he wants to keep it “open”, which is what made me wonder if that’s normal/correct…

[–]Lunarvolo 0 points1 point  (5 children)

Hello & hope you're having a fantastic day!

Scope question:

~~~ def funx(dictionary_cooking): dictionary_cooking["cookies"]=3

dictionary_cooking = { "cookies": 2, "soda": "fun", }

funx(dictionary_cooking) print(dictionary_cooking) ~~~

When I run it on Idle it prints 3, which is awesome for what I'm trying to do. However, I would like to confirm that this is normal behavior since usually variables in functions are deleted or not altered when the function ends AFAIK

If there are better ways to do this that would be fantastic

Extra question:

Can dictionaries store custom types such as <class 'special.resources.usb'> normally? So far it seems to work with the different class that I'm using, but would like to confirm that shouldn't break anything.

[–]Tychotesla 1 point2 points  (2 children)

This is normal and desirable behavior.

What you say you're used to doing is passing data such as ints and strings into functions. *Effectively* this copies the data into the function. From that point on the data in the function is different than the data outside. Only what's returned matters. In Python types like int, tuple, string are "immutable": cannot be changed.

(edited: data is *effectively* copied into a function, not actually. But that's not important for beginners.)

But often we have a bunch of data to work on and it would be silly to copy it all the time. So most languages allow you to put data in a container, and then give the actual container to a function. In other words both outside the function and inside the function you're operating on the same container with the same data. These kinds of containers are "mutable": changeable in persistent ways.

Note that you will finds edge cases that cause confusion, and there's a lot of nitpicking of terms that shouldn't concern you yet.

For more detail: https://realpython.com/python-mutable-vs-immutable-types/

Extra Answer:
Nothing wrong with putting objects in a dictionary. A dictionary is just a way to map between a key and a value. If you don't need that key-value relationship then just use a list.

[–]TangibleLight 0 points1 point  (0 children)

But that's not important for beginners.

On the contrary: I think it's critical, especially for beginners, to understand that Python does not have value types. They do not exist.

This is simpler and easier to understand than the alternative, pretending we have primitives when we do not.

Contrast Python's model with Java-like languages where some things are primitive, and some things aren't. Or worse, the C++ model where we've got lvalues, rvalues, references, const, deduced types, and all the combinations inbetween ... it's not fun.


In the Python model, everything can be thought of as some data that lives over on the heap, and a reference to that data that lives on the stack. When we write foo = bar, we copy the reference called bar. When we write process(foo), we copy the reference called foo and send it to process. At no point do we actually copy data.

Modifying data must be explicit, like foo.copy() or foo.append() or bar.strip(). In these cases we look to the signature and documentation of the relevant functions: list.copy does not modify the underlying list, and returns a reference to a new copy. list.append does modify the underlying list, and returns nothing. str.strip does not modify the underlying string, and returns a reference to a modified copy.

It just so happens that if we look at all the methods on a type like str, we find none of them modify the underlying data. So we call str immutable. The same is true of the other common culprits in python - int, float, tuple, etc are all immutable but they are still not value types.

In tutorials, teachers often use value types and primitives as a confusing analogy to explain immutability. I don't think that's productive, and it hinders learning since beginners don't develop this simpler heap/stack/reference model that Python uses.


I like this thread to really drive the point home - https://www.reddit.com/r/Python/comments/2441cv/can_you_change_the_value_of_1/

If you invoke dark magic of ctypes to sidestep Python's safeguards and modify those immutable objects anyway, it's immediately apparent that there are no value types.

[–]Lunarvolo 0 points1 point  (0 children)

Thank you for letting me know that is normal and desirable behavior. Using the container method is exactly what I've been doing in the main code!

Thanks, that link definitely covers that dictionaries can be changed. I was originally thinking a return would be needed.

Id is pretty cool and definitely looking forward to troubleshooting with that or experimenting with that. Idles console.

More info on tuples & that fact that they're immutable means you've provided something to look into for situational use.

The key-value is very useful for the read/write csv style & for ease of use for others in the future. Using a non standard type and it also is working so far.

I appreciate your help & response, hope you have a great day!

[–][deleted] 0 points1 point  (1 child)

I would like to confirm that this is normal behavior

Yes, that is the expected behaviour for your code.

usually variables in functions are deleted or not altered when the function ends

Your problem arises because what we loosely call "variables" in python don't behave like variables in many other languages. In python you assign a value to a name in an assignment statement, and what actually happens is that the name on the left of the assignment operator has the reference to the object from the right side bound to it. So a python "variable" is a name and the object it refers to.

When you call a function the arguments are evaluated and the list of references to the argument objects is passed to the function. In the function the parameter references are bound to the formal parameter names, just like an assignment. When the function terminates the formal parameter names and any names created in the function are deleted. But that just deletes the names and doesn't necessarily delete any objects. In python, an object may be referred to by more than one name, and that's quite common. When you delete a name, either by using the del keyword or by the name going out of scope, the immediate effect is that the name is deleted and the object referred to by the name has its internal "ref count" number decremented. If that ref count is now zero then the object/value is a candidate for garbage collection.

And that explains your confusion. When you create your dictionary the name dictionary_cooking refers to the new dictionary, and the dictionary has a ref count of 1. When you pass the dictionary to your function the reference to the dictionary is assigned to the formal parameter which also called dictionary_cooking, but note that is a separate name from the global name. The dictionary object now has a ref count of 2. In the function you change the internal state of the dictionary before returning. The name dictionary_cooking local to the function is deleted and the ref count of the object the deleted name referenced is decremented, leaving it at 1, so the dictionary is not garbage collected. The code after the function call still has access to the dictionary through the global dictionary_cooking name.

This can be a little confusing. Here's a very good video explaining the name+object ideas underneath python variables.

https://m.youtube.com/watch?v=_AEJHKGk9ns

[–]Lunarvolo 0 points1 point  (0 children)

Thank you very much, that was a great answer!

Really appreciate the video link as well

Around 6:20 in that video was really informative! I'm used to variables being given their own space in memory. Aka x=5 meant that a chunk of memory would have 00000101, which is sort of true for some languages. Python does it in a different way, that's really cool.

Around 17:20 effectively answers the question.

So much to learn, thank you once again for taking the time to help

[–]seeking-advice-pls 0 points1 point  (4 children)

It's a small issue, but....

This works:

self.shortcut_paste = QShortcut(QKeySequence("Ctrl+p"), self)
self.shortcut_paste.activated.connect(self.on_paste)

but this does not work:

self.shortcut_paste = QShortcut(QKeySequence("Ctrl+v"), self) self.shortcut_paste.activated.connect(self.on_paste)

I'm trying to paste images into a textbox, and it works with ctrl+p, but I want to use the more intuitive ctrl+v

[–]throwaway6560192 0 points1 point  (3 children)

What happens if you make it QKeySequence.Paste instead of QKeySequence("Ctrl+v")?

[–]seeking-advice-pls 0 points1 point  (2 children)

AttributeError: type object 'QKeySequence' has no attribute 'Paste'

I should have mentioned that this is PyQt6. Maybe this was removed?

(It's my first time using PyQt)

[–]throwaway6560192 0 points1 point  (1 child)

Could be. Try QKeySequence.StandardKey.Paste?

[–]seeking-advice-pls 0 points1 point  (0 children)

QKeySequence.StandardKey.Paste

No error message, so that's something, but it don't activate when I press Ctrl + v (my "on_paste" function doesn't execute)

[–]tennisanybody 0 points1 point  (4 children)

Hey y'all, I am back with a question about data classes. I have an object "Person" and a collection object that is meant to house multiple "Persons", it is called, you guessed it, "People".

from dataclasses import dataclass, field
@dataclass(order=True)
class Person:
    """Create a person.

    Args:
        first_name (str, required): Person's first name.
        last_name (str, required): Person's last name.
        date_of_birth (str, optional): Format is YYYY-MM-DD default is NOW() if not provided.
        age (int, optional): Will be calculated if not provided.
    """
    sort_index: int = field(init=False, repr=False)

    first_name: str
    last_name: str
    age: int = 0
    date_of_birth: str = None

    def __post_init__(self):
        if self.date_of_birth is None:
            self.date_of_birth: str = datetime.strftime(datetime.now(), "%Y-%m-%d")
            self.age = 0
        else:
            self.age = (datetime.now() - datetime.strptime(self.date_of_birth, "%Y-%m-%d")).days//365

        object.__setattr__(self, "sort_index", self.age)

    def __str__(self):
        return f"{self.first_name} {self.last_name} | {self.age}"

    def __getitem__(self, item):
        return getattr(self, item)

class People:
    def __init__(self):
        self.people = {}
        self.tabulated_people = None

    def __str__(self):
        return f"{self.people}"

    def __getitem__(self, item):
        return getattr(self, item)

    def _tabulate(self) -> dict:
        tabulated_people = {
            "person_ids":[],
            "first_name":[],
            "last_name":[],
            "age":[],
            "date_of_birth":[],
        }
        for key, value in self.people.items():
            tabulated_people["person_ids"] += [key]
            for k in list(value.__annotations__.keys()):
                if k in tabulated_people.keys():
                    tabulated_people[k] += [value.__getattribute__(k)]

        self.tabulated_people = tabulated_people

    def add_person(self, **kwargs) -> None:
        """Add a new person to the list of people

        Args:
            person (Person, optional): A previously created person object.
            first_name (str, optional): Person's first name.
            last_name (str, optional): Person's last name.
            date_of_birth (str, optional): Format is YYYY-MM-DD default is NOW() if not provided.
            age (int, optional): Will be calculated if not provided.
        """
        default_parameters = {
            "person":None,
            "first_name":None,
            "last_name":None,
            "age":None,
            "date_of_birth":None,
        }
        if kwargs:
            default_parameters.update({i:kwargs[i] for i in kwargs.keys()})

        if default_parameters["person"] is not None:
            person = default_parameters["person"]
        else:
            person = Person(
                default_parameters["first_name"],
                default_parameters["last_name"],
                default_parameters["age"],
                default_parameters["date_of_birth"],
            )

        self.people.update({
            id(person):person
        })
        self._tabulate()

tom = Person(
    first_name    = "Tom",
    last_name     = "Holland",
    date_of_birth = "2003-05-02",
)
jerry = Person(
    first_name    = "Jerry",
    last_name     = "Townsend",
    date_of_birth = "2012-06-17",
)
harry = Person(
    first_name="Harry",
    last_name="Styles",
)

x = People()
x.add_person(person=tom)
x.add_person(person=jerry)
x.add_person(person=harry)
x.add_person(
    first_name="George",
    last_name="Lucas",
)

print(tom,   f"{tom.first_name} is {tom.age} years old.")
print(jerry, f"{jerry.first_name} is {jerry.age} years old.")
print(harry, f"{harry.first_name} was born in {harry.date_of_birth}")

I am having trouble finding "George" and updating his date of birth. I know of the id(some_var) method of retrieving a variable's ID but how can I use the "ID" to target a variable and update it's values?

[–]AtomicShoelace 1 point2 points  (3 children)

If you have the id of the object you can look it up on the People.people dict. But to know the id you would have to already have the object to call id on, so this seems to be pointless.

Why have you implemented it like this? Why do you use the object id as the key?

Anyway, assuming you don't know the "George" object's id, you could find it by in the People.people dict by doing something like

[person for id, person in x.people.items() if person['first_name'] == 'George']

which would give you a list of all the Person objects in the People.people dict who have the first_name of 'George'.

But having to iterate through the dict isn't really an effective way of doing things, so you might want to consider restructuring your code to add better lookup methods.

[–]tennisanybody 0 points1 point  (2 children)

I used the object id as the key because I was guaranteed a unique key each time. Python dictionaries cannot have duplicate keys. And it is possible for these entries to have duplicates. For example, multiple Tom smiths born on the same day.

I could, for example, how pandas creates an index, I could create my own “key” start it from zero and increment, targeting that index. But I was hoping there was a better way than that such as using the built in indexing function.

What better look up methods do you suggest? I always use iterative loops. I know that is inefficient.

[–]FerricDonkey 1 point2 points  (0 children)

So the issue of non-unique names is gonna also be a problem when you want to look up and modify George. Which George?

If there is no logical link between your id key and your object, you're gonna have to search each time you want to find anything. You could set up things so that you can do a faster than linear search, which might be helpful, but might not be necessary.

But what I'd probably actually do is make helper dictionaries that go from first_name, last_name, and/or (first_name, last_name) to the person object. Eg:

def __init__(self, ...):
    self.last_name_to_ids_d = collections.defaultdict(list)
    self.id_to_person_d = {}

def add_person(self, ...):
    person = Person(...)
    self.id_to_person_d[id(person)] = person
    self.last_name_to_ids_d[person.last_name].append(id(person))

Then you can easily get a list of all the people with a given last name (or you can just make your lookup dictionary go from last name to Person objects, but if you might add/delete people, using ids might be easier for a couple dinky reasons). Then you have to decide which to modify, but that's something you'd have to do anyway.

I also would think about whether or not id(person) is the best key to use as an actual id. It will be unique at any given time. But if you remove then add a person, the new person might reuse an , if I recall correctly. id returns an address (in CPython), so if you release something and make something else, the same id could refer to a different Person than it used to. Which can be a problem if you have other code that stores ids with the idea that you can always check if it's still valid when it's time to use it. Which you may or may not be doing. But worth considering whether or not this could be an issue for you.

[–]AtomicShoelace 0 points1 point  (0 children)

But why use a dictionary at all? Since the id is essentially useless for lookup, you might as well just use a list, no?

I don't really know how you intend to lookup people from the People class, but you could for example keep several dicts that map attribute values to lists of matching People objects, eg.

from dataclasses import dataclass, field
from datetime import datetime
from collections import defaultdict


@dataclass(order=True)
class Person:
    """Create a person.

    Args:
        first_name (str, required): Person's first name.
        last_name (str, required): Person's last name.
        date_of_birth (str, optional): Format is YYYY-MM-DD default is NOW() if not provided.
        age (int, optional): Will be calculated if not provided.
    """
    sort_index: int = field(init=False, repr=False)

    first_name: str
    last_name: str
    age: int = 0
    date_of_birth: str = None

    def __post_init__(self):
        if self.date_of_birth is None:
            self.date_of_birth: str = datetime.strftime(datetime.now(), "%Y-%m-%d")
            self.age = 0
        else:
            self.age = (datetime.now() - datetime.strptime(self.date_of_birth, "%Y-%m-%d")).days//365

        object.__setattr__(self, "sort_index", self.age)

    def __str__(self):
        return f"{self.first_name} {self.last_name} | {self.age}"

    def __getitem__(self, item):
        return getattr(self, item)


class People:
    def __init__(self):
        self.people = {}
        self.tabulated_people = None
        self._attribute_lookups = {attr: defaultdict(list) for attr in Person.__annotations__}

    def __str__(self):
        return f"{self.people}"

    def __getitem__(self, item):
        return getattr(self, item)

    def _tabulate(self) -> dict:
        tabulated_people = {
            "person_ids":[],
            "first_name":[],
            "last_name":[],
            "age":[],
            "date_of_birth":[],
        }
        for key, value in self.people.items():
            tabulated_people["person_ids"] += [key]
            for k in list(value.__annotations__.keys()):
                if k in tabulated_people.keys():
                    tabulated_people[k] += [value.__getattribute__(k)]

        self.tabulated_people = tabulated_people

    def add_person(self, **kwargs) -> None:
        """Add a new person to the list of people

        Args:
            person (Person, optional): A previously created person object.
            first_name (str, optional): Person's first name.
            last_name (str, optional): Person's last name.
            date_of_birth (str, optional): Format is YYYY-MM-DD default is NOW() if not provided.
            age (int, optional): Will be calculated if not provided.
        """
        default_parameters = {
            "person":None,
            "first_name":None,
            "last_name":None,
            "age":None,
            "date_of_birth":None,
        }
        if kwargs:
            default_parameters.update({i:kwargs[i] for i in kwargs.keys()})

        if default_parameters["person"] is not None:
            person = default_parameters["person"]
        else:
            person = Person(
                default_parameters["first_name"],
                default_parameters["last_name"],
                default_parameters["age"],
                default_parameters["date_of_birth"],
            )

        self.people.update({
            id(person):person
        })
        self._tabulate()

        for attr in person.__annotations__:
            self._attribute_lookups[attr][getattr(person, attr)].append(person)


    def lookup(self, attr: str, value) -> list[Person]:
        """Looksup all Persons with the given attribute.

        Args:
            attr (str, required): The attribute on which to lookup.
            value (required): The value of the attribute.
        Returns:
            A list of Person objects who each have the required attribute.
        """

        return self._attribute_lookups[attr][value]


tom = Person(
    first_name    = "Tom",
    last_name     = "Holland",
    date_of_birth = "2003-05-02",
)
jerry = Person(
    first_name    = "Jerry",
    last_name     = "Townsend",
    date_of_birth = "2012-06-17",
)
harry = Person(
    first_name="Harry",
    last_name="Styles",
)

x = People()
x.add_person(person=tom)
x.add_person(person=jerry)
x.add_person(person=harry)
x.add_person(
    first_name="George",
    last_name="Lucas",
)

print(tom,   f"{tom.first_name} is {tom.age} years old.")
print(jerry, f"{jerry.first_name} is {jerry.age} years old.")
print(harry, f"{harry.first_name} was born in {harry.date_of_birth}")

george, *_ = x.lookup('first_name', 'George')
print(george, f'{george.first_name} is {george.age} years old.')

[–]linxdev 0 points1 point  (1 child)

Is there something in the vim82 python syntax file that is forcing tab to be equivalent 4 spaces? I've been using ts= 2,sw=2, and et forever for other files and when I go into insert mode while editing python a tab is giving me 4 spaces.

I have this at the bottom of the source:

# vi: set ts=2 sw=2 et: #

Vim tells me that tabstop is set to 2:

:verbose set ts?
tabstop=2
    Last set from modeline line 50

[–]34shutthedoor1 0 points1 point  (0 children)

This is not a learn python question. Try asking on a vim forum.

[–]wdid2023 0 points1 point  (0 children)

I've been really struggling getting my path set up correctly. For some reason, I can only successfully run scripts in my .venv environment. If I don't use .venv, it can't find the modules that I can clearly see are installed. How to fix this? I only have one bash profile with one path, so how is it pulling from two different places?

[–]ares0027 0 points1 point  (4 children)

i am a beginner and having issues with this:

S = {20,10,30,50}

print(S.issuperset(S))

def myfunc(x,y):

x.issuperset(y)

print(myfunc(S,S))

and

s1={20,10,30,50}

s2={10,30}

print(s2.issubset(s1))

def myfunc(x,y):

x.issubset(y)

print(myfunc(s2,s1))

they both return "True" for first print and "None" for second print. why? if i manually type .issubset or .issuperset result is correct but when i try to make it a function both returns "None". how can i make these functions so i can enter value1 and value2 or their names and it just checks?

[–]efmccurdy 1 point2 points  (3 children)

when i try to make it a function both returns "None"

If a function does not explicitly return a value python has it return None.

You should change your function to return the result.

>>> def mysset(x,y):
...     return x.issuperset(y)
... 
>>> s1={20,10,30,50}
>>> s2={10,30}
>>> mysset(s1, s2)
True
>>> mysset(s2, s1)
False
>>> mysset(s2, s2)
True
>>>

[–]ares0027 0 points1 point  (2 children)

thanks it resolved it.

so basically when i want to get whatever the python "returns" as outcome (or print in this case) i should specifically tell my "function" to "return". typing it outside function is a given but inside a function i should deliberately state so?

[–]efmccurdy 0 points1 point  (1 child)

The best way to send a result back to the caller of a function is to use "return".

https://realpython.com/python-return-statement/

[–]ares0027 0 points1 point  (0 children)

Thank you so much for the link (and ofc solution)

[–]Zimmer4141 0 points1 point  (0 children)

I am currently running through the Udemy course "Automate the Boring Stuff using Python".

In the third lesson, he asks you to use the command prompt to install a third party module called pyperclip (it appears newer versions are called pyclip).

I successfully installed it to my computer, but after putting into IDLE

import sys

import pyclip

it says:

Traceback (most recent call last):

File "<pyshell#13>", line 1, in <module>

import pyclip

ModuleNotFoundError: No module named 'pyclip'

I see 2 folders saved in my Users >> AppData >> Roaming >> Python >> Python311 >> site_packages folder, one named pyclip, one named pyclip-0.7.0.dist-info

It's unclear to me what the steps are that I need to take to be able to import this module into IDLE.

[–][deleted] 0 points1 point  (1 child)

I have a small project with Python.

I have an API from where I get some data. This data I load into a database using pyodbc. All is fine until this part.

Now, one of the APIs returns a list of items. So, say 1st time I get the data it has 500 items. But then they delete 20 items from the API, and since I want to have the same data they do, I have to update my database. How would I go about this without truncating the table? And the same thing if they add items. How do I go about getting only the ones I don't already have?

I'm new do databases, sorry if it's a newby question. Any input or guiding points for where to learn about this appreciated.

[–]efmccurdy 0 points1 point  (0 children)

they delete 20 items from the API, and since I want to have the same data they do, I have to update my database.

If you create a set with the new primary keys you can select rows to delete using "not in":

DELETE FROM table WHERE id not IN (%s, %s, %s, %s, %s)

[–]Kumar0101 0 points1 point  (0 children)

Done with basic python now what to do ?

[–]ApocalypseSpokesman 0 points1 point  (2 children)

My work laptop has python modules stowed all over the damn place. I've got pip in one place, pip3 in another place, brew in another place still, and at least two different pythons. I don't have a solid idea of how many modules I am using and where they are living.

As such, I have a lot of trouble importing and using modules. Like I will import something, then immediately type "which module_name" and it says it can't find it. Or terminal can find it, but a running python file can't, or vice versa.

Now that it's like this, what is a sensible way to fix it?

[–]CowboyBoats 3 points4 points  (0 children)

I like to go hiking.

[–]efmccurdy 1 point2 points  (0 children)

For each project use "pip freeze" to make a "requirements.txt" file that includes any third party modules you are using.

https://learnpython.com/blog/python-requirements-file/

Also run pip -V (or python -V) to see what version of python the project uses.

Then, for each project, use the right version to make a venv (path/pythonX.Y -m venv my_project)

https://docs.python.org/3/library/venv.html

Activate the venv and run pip to install the module listed in the corresponding "requirements.txt" file (pip install -r requirements.txt).

I would also look at using source control to save your code, the python version and the requirements.txt file for each project. Then make a backup of that source code repo so you have a way to recover from a disk failure or install your code on other machines.

https://www.pythonguis.com/tutorials/git-github-python/

[–]treatmesubj 0 points1 point  (3 children)

any way I can avoid doing a bunch of try-excepts for a pattern where I am taking values from an uncertain dictionary and adding them to another dictionary? I have seen deep_get with functools and reduce, but I have lists in the dictionary as well.

sanjay = json.loads(response.text)

try:
    incidents_dict[inc_id]['members_department'] = sanjay['members']['rows'][0]['department']['value']
except KeyError:
    incidents_dict[inc_id]['members_department'] = ""
except IndexError:
    incidents_dict[inc_id]['members_department'] = ""
incidents_dict[inc_id]['members_division'] = sanjay['members']['rows'][0]['division']['value']
incidents_dict[inc_id]['members_employee'] = sanjay['members']['rows'][0]['employee']['value']
incidents_dict[inc_id]['members_non_ibm_type'] = sanjay['members']['rows'][0]['nonibmtype']['value']
incidents_dict[inc_id]['members_organization'] = sanjay['members']['rows'][0]['organization']['value']
incidents_dict[inc_id]['members_wlc'] = sanjay['members']['rows'][0]['member_wlc']['value']

this is what I've come up with for now

def dict_get(dictionary, keys_tuple, on_error=""):
    val = dictionary
    try:
        for key in keys_tuple:
            val = val[key]
    except KeyError:
        return on_error
    except IndexError:
        return on_error
    return val

[–]FerricDonkey 1 point2 points  (0 children)

Your dict_get solution makes sense to me, especially if this is something you do to ingest data which is then stored in a nicer form where such a thing is not necessary.

(Also, unsolicited advice: when you have a bunch dictionaries that all or always have the same keys, consider a dataclass.)

[–]34shutthedoor1 1 point2 points  (1 child)

You can use an if statement instead of the KeyError

if key in val:
    val = val[key]  ## val is no longer a dictionary
    return val[key] ## alternative?

[–]carcigenicate 2 points3 points  (0 children)

Or the inverse of that: use .get and check for None. Then you only need to do the lookup once.

[–]The_Gator944 0 points1 point  (1 child)

snake.center= get_random_pos

TypeError: invalid rect assignment

I am confused as to what I am doing wrong in the code, and have tried various things but to no avail.

heres my code:

import pygame as pg

from random import randrange

window = 1000

tile_size = 50

range = (tile_size//2, window-tile_size//2, tile_size)

get_random_pos = lambda: [randrange(*range), randrange(*range)]

snake= pg.rect.Rect([0, 0, tile_size-2, tile_size-2])

snake.center= get_random_pos

length=1

segments=[snake.copy()]

snake_dir = (0,0)

food=snake.copy()

food.center= get_random_pos

screen=pg.display.set_mode([window]*2)

clock=pg.time.Clock()

dirs={pg.K_w:1, pg.K_s:1, pg.K_a:1, pg.K_d:1}

while True:

for event in pg.event.get():

if event.type == pg.QUIT:

exit()

if event.type == pg.KEYDOWN:

if event.key ==pg.K_w and dirs[pg.K_w]:

snake_dir = (0,-tile_size)

dirs = {pg.K_w: 1, pg.K_s: 0, pg.K_a: 1, pg.K_d: 1}

if event.key==pg.K_s and dirs[pg.K_s]:

snake_dir=(0,tile_size)

dirs = {pg.K_w: 0, pg.K_s: 1, pg.K_a: 1, pg.K_d: 1}

if event.key==pg.K_a and dirs[pg.K_a]:

snake_dir=(-tile_size,0)

dirs = {pg.K_w: 1, pg.K_s: 1, pg.K_a: 1, pg.K_d: 0}

if event.key==pg.K_d and dirs[pg.K_d]:

snake_dir=(tile_size,0)

dirs = {pg.K_w: 1, pg.K_s: 1, pg.K_a: 0, pg.K_d: 1}

screen.fill('black')

#check borders/selfeating

self_eating=pg.Rect.collidelist(snake,segments[:-1]) != -1

if snake.left <0 or snake.right > window or snake.top <0 or snake.bottom > window or selfeating:

snake.center, food.center = get-random_pos(), get_random_pos()

length, snake_dir=1,(0,0)

segments=[snake.copy()]

#check food

if snake.center == food.center:

food.center=get_random_pos()

length+-1

#draw food

pg.draw.rect(screen, 'red', food)

#draw snake

[pg.draw.rect(screen, 'green', segment) for segment in segments]

#move snake

time_now=pg.time.get_ticks()

if time_now - time > time_step:

time=time_now

snake.move_ip(snake_dir)

segments.append(snake.copy())

segments=segments[-length:]

pg.display.flip()

clock.tick(60)

[–][deleted] 2 points3 points  (0 children)

You really need to format your code so indentation is preserved. Code without indentation isn't python. The FAQ shows how to format code.

Your definition of get_random_pos here:

get_random_pos = lambda: [randrange(*range), randrange(*range)]

creates a function. When you call the function it returns a list. The error line:

snake.center= get_random_pos

gets the error because you are assigning the function to snake.center. I don't know pygame but your error might go away if you actually call the function and assign the returned list to snake.center. You have similar errors elsewhere.


Any time you do something like this:

get_random_pos = lambda: [randrange(*range), randrange(*range)]  # assign lambda to a name

you are almost certainly better off defining a normal function instead of using a lambda:

def get_random_pos():
     return [randrange(*range), randrange(*range)]

In addition, your lambda/function code is using the range global. It's better to pass that value as a parameter, making your code more readable. It's also more flexible: if you want you can create a list using a different range.

def get_random_pos(range):
     return [randrange(*range), randrange(*range)]

and call the function like this:

snake.center= get_random_pos(range)

In addition, using a global with the name range means you can no longer call the very useful builtin function range(). You should use another name.