This question already has answers here:
What is the purpose of the `self` parameter? Why is it needed?
(26 answers)
Closed 4 months ago.
I am trying to write a class that allows users to register on a platform with a username, but checks that this username does not exist in the database.
I have this code:
class Freelancer:
"""Leaving this blank for now while I explore the functionality """
number_of_sales = 0
available_niches = ["Graphic design", "Art", "Data Analysis", "Music", "Business", "Writing and Translations"]
usernames = []
def __init__(self, username):
self.username = _check_username(username)
def _check_username(self, username):
if self.username in Freelancer.usernames:
print("This username already exist on our database, consider choosing another one")
else:
self.username = username
Freelancer.usernames.append(self.username)
print("You have successfully setup a username on our platform")
which I tested like so:
David = Freelancer("dave23")
But I got an exception: NameError: name '_check_username' is not defined. What is wrong with the code? How can I call a private method from __init__?
You missed self before calling private method.
def __init__(self, username):
self.username = self._check_username(username)
If it is still gives error like: 'Freelancer' object has no attribute 'username'
define username variable
First of all, __init__ is not the constructor.
Note that __init__(self) already has the object (self), so it was already constructed before calling __init__. (The real constructor in Python is __new__).
Python does not have private methods, no matter how many underscores you add.
This should work:
def __init__(self, username):
self.username = self.check_username(username)
def check_username(self, username):
...
You could add the leading underscore to indicate that the method is for internal use only.
There is however another mistake in the code. It should be:
def _check_username(self, username):
if self.username in self.usernames: # <-----
print("This username already exist on our database, consider choosing another one")
else:
self.usernames.append(self.username) # <-----
return username
You are manipulating the class. That means that if the class is instantiated again usernames is not empty.
Related
I am writing a class that stores credentials. The credential can have a password_getter attribute which stores a lambda that will get the password on-demand. This getter needs access to self.username in order to function. How can this be accomplished? Consider the following setup:
class Credential:
"""Defines one username and password combination, and how to get them."""
def __init__(self, username: str, password_getter: callable):
self.username = username
self._password_getter = password_getter
#property
def password(self) -> str:
self.password = self._password_getter()
return self.password
Then we define a new credential:
cred = Credential(
username="test",
password_getter=lambda self: self.username+"_pass",
)
assert cred.password == "test_pass"
The above is non-functional due to self not existing during definition, but it suggests what I'm trying to do: Access the current value of cred.username from inside the lambda.
For some context as to why this is happening; the function in production actually goes out to a password vault api and requests the password for the given username.
The Callable you pass in has no intrinsic connection to the instance, so your two options are to give it implicit or explicit access. Implicit would rely on simple closures:
cred = Credential(
username="test",
password_getter=lambda: cred.username + "_pass",
)
The problem here is if you reassign cred later and it refers to the wrong instance when trying to get the password.
The explicit alternative is:
cred = Credential(
username="test",
password_getter=lambda instance: instance.username + "_pass",
)
...
#property
def password(self) -> str:
self.password = self._password_getter(self)
The class explicitly passes itself to the password getter. So it should be typed as Callable[[Credentials], str], i.e. something that receives an instance of the class as argument and is expected to return a string.
For example
class Signup:
def __init__(self): # i want to call the functions in this class
self.user_input()
self.get_password()
def user_input(self):
username = input("Enter your username: ")
return username
def get_password(self):
password = input("Enter a password: ")
return password
class Data(Signup):
def __init__(self):
super().__init__()
self.username = self.user_input() # When I call these two functions they execute it again
self.password = self.get_password()
So I want the string to be returned when I call those functions in the Data class. The problem is that the function calls itself here again too.
And I know I can just call the functions inside the Data class, but I want to call it in the Signup class and get the string back inside the Data class.
Thanks!
Hey there I'm new to python and try to program a simple login module which salts a password
When I use this class I get the following error:
TypeError: salting() missing 1 required positional argument: 'password'
class Login():
def salting(self, username, password):
self.password = password
self.username = username
print(self.username + self.password)
Login.salting("user1","pw1")
My Only Solutions were to use Login.salting("","user1","pw1") with an empty string for self or calling self as username end reuse it like this, but I think that I ran in an error, can someone help me :D
But when I compare that with my previous code which was like this (I learned that with this code) - the error doesn't appear...
class car():
name = "BMW"
color = "red"
def redesign(self, color):
self.color = color
c = car()
print(c.name)
print(c.color)
c.redesign("blue")
print(c.color)
THANKS
salting is an object method, not a class method. Each object has its own username and password attributes. You need to create a Login object, and then call the method on that.
s = Login()
s.salting("user1", "pw2")
This is analogous to using c = car() in the second block of code.
I am trying to achieve the following:
class A:
username = None
username = get_username()
def get_username(self):
if username is None:
try:
uname = os.environ["USER"]
except:
printf("Couldn't find a user name")
return uname
return username
Not sure how to achieve this. I'm sure I'm missing some "self." prefixes but this is the first time I'm working with python and static members.
In a sense I want a class with some members and functions to calculate values for these members but I don't want recalculations. I would also like these to be static functions and data members.
The problem is that the line "username = get_username()" the function hasn't already been defined. If I put username after the function then it's not
First, there's no reason to assign None to username if you're just going to reassign it immediately after.
Second, if you want the method to be a static method, you can't give it a self argument. And if you want a real static method, you have to declare it explicitly.
#staticmethod
def get_username():
if username is None:
...
Otherwise, you need an instance of the class (that self) to call it on, and you don't have one yet.
In Python 3, any regular method acts like a static method when called on the class, like an instance method when called on an instance. So, if you're sure you're never going to want to call a.get_username() on an instance a, you can skip the decorator. But you still need to get rid of the self parameter.
I think what you're actually trying to do is use a class variable to memoize the result of a static method. You can't do that, but you can use a class variable to memoize the result of a class method, which may be close enough. That would look like this:
class A:
username = None
#classmethod
def get_username(cls):
if cls.username is None:
try:
uname = os.environ["USER"]
except:
print("Couldn't find a user name")
else:
cls.username = uname
return cls.username
On the other hand, there's no good reason username has to be a class member. You can memoize by adding a member to the function, by passing a mutable default variable, or in various other ways which don't require infecting the class, and which allow you to leave get_username as a static method instead of a class method.
But really, the best solution is to find a memoization library on PyPI, in ActiveState's recipe list, etc., so you can just write this:
class A:
#memoize
#staticmethod
def get_username():
try:
return os.environ["USER"]
except:
print("Couldn't find a user name")
return None
Again, you can drop the #staticmethod if you're sure nobody's ever going to try to create an instance of A and call get_username on it.
if you don't want to lose the ability to refer to A.username, you can use class property with a little bit of metaclass:
class A(type):
def __new__(cls, name, bases, attrs):
# this allows B().username to also work
attrs['username'] = property(lambda s: s.__class__.username)
return type.__new__(cls, name, bases, attrs)
#property
def username(self):
if not hasattr(self, '_username'):
self._username = 'bar'
return self._username
class B(object):
__metaclass__ = A
print B.username
print B().username
I have this form class :
class MyForm(forms.Form):
def __init__(self, *args, **kwargs):
self.notvalidate = kwargs.pop('notvalidate',False)
super(MyForm, self).__init__(*args, **kwargs)
email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,maxlength=75)))
(...)
if not notvalidate:
def clean_email(self):
email = self.cleaned_data.get("email")
if email and User.objects.filter(email=email).count() > 0:
raise forms.ValidationError(
_(u"Email already used."))
return email
Although in init I set self.notvalidate value to either True(if was given) or False inside the body of MyForm I'm getting name 'notvalidate' is not defined (or if I check for self.notvalidate - name 'self' is not defined). What is wrong ?
Move the if not notvalidate into the clean_email method, and reference it using self.notvalidate.
def clean_email(self):
if not self.notvalidate:
email = self.cleaned_data.get("email")
if email and User.objects.filter(email=email).count() > 0:
raise forms.ValidationError(
_(u"Email already used."))
return email
Also, you may want to rename the flag to should_validate_email and lose the negation.
What are you trying to achieve is changing the class level attribute clean_email but you want to do that using instance attribute self.notvalidate, so you are doing contradictory things here. Simplest way to not validate would be to check in clean_email and return e.g
def clean_email(self):
if self.notvalidate:
return
....
But if due to some mysterious reason you do not want clean_mail method to be existing in the class at all, you need to create a class using metaclass or simpler way would be to call a function to create class e.g.
def createFormClass(validate):
class MyClass(object):
if validate:
def clean_email(self):
pass
return MyClass
MyClassValidated = createFormClass(True)
MyClassNotValidated = createFormClass(False)
Though I will strongly suggest NOT to do this.
Change notvalidate to self.notvalidate.