throw variables into an error when initializing a class - python

class Person:
def __new__(cls, *args):
if not all(isinstance(x, str) for x in args):
raise TypeError(
f'invalid argument {1??} in {invalid_person??}'
f'{last_name??} must be string'
)
return super().__new__(cls)
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def __str__(self):
return f'{self.first_name} - {self.last_name}'
if __name__ == '__main__':
person = Person('john', 'dow')
print(person)
# error here
invalid_person = Person('john', 1)
Hello. this is example.
how to output an error in which place the error occurred, the name of the argument, the name of the attributes in the class and the name of the instance of the class?
Or maybe there is a better way to implement validation when instantiating a class?

Related

How to format strings in classes using attributes?

I want to format an attribute-string of a class with another attribute of the same class like this:
class Test:
def __init__(self):
self.name = None
self.full_name = 'name, {}'.format(self.name)
def print_name(self):
print(self.full_name)
my_object = Test()
my_object.name = 'my_object'
my_object.print_name()
Now it should print 'name, my_object'
But it prints 'name, None'
What to do that the string formats with the assigned value of the object?
You need to add full_name as a property so that you can add some more logic to it:
class Test:
def __init__(self):
self.name = None
#property
def full_name(self):
return f'name, {self.name}'
def print_name(self):
print(self.full_name)
my_object = Test()
my_object.name = 'my_object'
my_object.print_name()
Resources:
property function (built-in)

set dictionary key function in python

I was wondering how to create a function to set the key of a dictionary. Consider the following class:
class Dog:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
Now lets instantiate the object:
a_dog = Dog("Berty", "Hollows")
Now I want to create a function, which returns either the first name or the last name, depending on which parameter I pass into it. My idea was something like:
def return_dogs_name(dog, get_dict_key(x)):
return dog.get_dict_key(x)
with
def get_dict_key(x):
return x
however, that does not work.
My desired output would look like
return_dogs_name(a_dog, get_dict_key("first_name"))
>>> Berty
How would such a function look like?
You can make use of getattr:
class Dog:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def return_dogs_name(dog, attrName):
return getattr(dog, attrName)
a_dog = Dog("Berty", "Hollows")
print(return_dogs_name(a_dog, 'first_name'))
Out:
Berty
You can create a dictionary within your function
class Dog:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
a_dog = Dog("Berty", "Hollows")
def return_dogs_name(dog,which_name):
return {'first': dog.first_name,'last': dog.last_name}.get(which_name,'unknown')
print(return_dogs_name(a_dog,'last'))
Output :
Hollows

transform class methods using parent class' decorator method

def greeting_decorator(original_function):
def return_function(*args):
name = 'John'
return f'Hi, I\'m {name}, fullname: {original_function(*args)}'
return return_function
#greeting_decorator
def greeting(name, surname):
return f'{name} {surname}'
print(greeting('John', 'Doe'))
Above, I have a simple decorator function that works as intended.
I'd like to do something similar, but with an inherited class.
How might I go about inheriting a decorator function like this:
class Guy:
def __init__(self, name):
self.name = 'John'
def greeting_decorator(self, original_function):
def return_function(*args):
return f'Hi, I\'m {self.name}, fullname: {original_function(*args)}'
return return_function
class GuyWithSurname(Guy):
def __init__(self, name, surname):
super().__init__(name)
self.surname = surname
#greeting_decorator # <----- here
def __str__(self):
return f'{self.name} {self.surname}'
JohnDoe = GuyWithSurname('John', 'Doe')
print(JohnDoe)
If you are certain that the parent class will always be Guy, you can simply annotate via #Guy.greeting_decorator:
class Guy:
def __init__(self, name):
self.name = 'John'
def greeting_decorator(original_function):
def return_function(self, *args):
return f'Hi, I\'m {self.name}, fullname: {original_function(self, *args)}'
return return_function
class GuyWithSurname(Guy):
def __init__(self, name, surname):
super().__init__(name)
self.surname = surname
#Guy.greeting_decorator # <----- here
def __str__(self):
return f'{self.name} {self.surname}'
JohnDoe = GuyWithSurname('John', 'Doe')
That way, when you call print(JohnDoe) it will output Hi, I'm John, fullname: John Doe.
Note that I had to change the greeting_decorator and the return_function parameters to properly handle self.

Add argument to function after it's already been called?

For example, if I have the function:
def to_full_name(first_name, last_name=None): # Note that 'last_name' is not required, so an error will not occur
return '{} {}'.format(first_name, last_name)
# ...
a = to_full_name('John')
How can I add the second argument to the 'a' variable later down the line? ex:
a.set_argument('last_name', 'Doe')
For this particular problem I would recommend a class.
class Person:
def __init__(self, first_name=None, last_name=None):
self.first_name = first_name
self.last_name = last_name
def set_first_name(self, name):
self.first_name = name
def set_last_name(self, name):
self.last_name = name
def to_full_name():
return '{} {}'.format(self.first_name, self.last_name)
Then we change it as follows
person = Person("John")
person.set_last_name("Doe")
print(person.to_full_name())
We can also change the values directly
person = Person()
person.last_name = "Doe"
person.first_name = "John"
print(person.to_full_name())

How to use class methods in python?

I have this code
class Person(object):
def __init__(self, name):
self.name = name
#classmethod
def from_classmethod(cls, name):
return cls(name)
p = Person.from_classmethod("Moctar")
p.name
But it shows the following error:
AttributeError: 'Person' object has no attribute 'name'
What could be going wrong here, or am i using wrongly the python #classmethod feature ?
As #furas says, what I think you want is:
class Person(object):
def __init__(self, name):
self.name = name
#classmethod
def from_classmethod(cls, name):
return cls(name)
p = Person.from_classmethod("Moctar")
print(p.name)
Result:
Moctar
It is the assignment to self.name that creates that attribute on the instance of Person that you are creating.

Categories